using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Diagnostics;

namespace Setup
{
    class Program
    {
        private const string MSBUILD_PROPERTIES_URN = "urn:sdc-microsoft-com:deployment:properties:v2.0";
        static void Main(string[] args)
        {
            if (args.Length < 2)
            {
                Console.WriteLine(String.Format("Wrong argument number were provided. Try: Setup.exe test.msi test.xml [/r] [/u]"));
                Console.WriteLine(String.Format("[/r] - reinstall"));
                Console.WriteLine(String.Format("[/u] - uninstall"));
                return;
            }

            String msiPath = args[0];
            String settingsFielPath = args[1];
            String logFile = Path.ChangeExtension(Path.GetFileName(msiPath), ".log");
            String installOptions = "/i";
            String optionalOptions = "";
            Dictionary<String, String> properties = GetMsiProperties(settingsFielPath);
            //properties.Add("MSI.PROPERTY.FILE", new FileInfo(settingsFielPath).FullName);

            if (args.Length > 2)
            {
                foreach (String arg in args)
                    if (String.Compare(arg, "/r", true) == 0)
                    {
                        properties.Add("REINSTALL", "ALL");
                        properties.Add("REINSTALLMODE", "vomus");
                    }
                    else if (String.Compare(arg, "/u", true) == 0)
                        installOptions = "/uninstall";
                    else if (arg.StartsWith("/"))
                        optionalOptions += arg + " ";
            }

            String msiProperties = ConvertDictionaryToCommandLine(properties);

            String arguments = String.Format("{3} {1} /log {0} {4} {2}", logFile, msiPath, msiProperties, installOptions, optionalOptions);

            Console.WriteLine("Command line is: msiexec" + arguments);

            Process p = System.Diagnostics.Process.Start("msiexec", arguments);
            p.WaitForExit();

            Console.WriteLine("Done with exit code:" + p.ExitCode);
        }

        static Dictionary<String, String> GetMsiProperties(String fileName)
        {
            XmlDocument doc = null;
            Dictionary<String, String> properties = new Dictionary<String, String>();

            try
            {
                doc = new XmlDocument();
                doc.Load(fileName);

                if (doc.DocumentElement.NamespaceURI == MSBUILD_PROPERTIES_URN)
                {
                    XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
                    nsmgr.AddNamespace("msbuidprop", MSBUILD_PROPERTIES_URN);
                    XmlNodeList list = doc.SelectNodes("/msbuidprop:Properties/msbuidprop:Property", nsmgr);


                    foreach (XmlNode node in list)
                    {
                        String propertyName = node.Attributes["Name"].Value;

                        if (properties.ContainsKey(propertyName))
                        {
                            System.Console.WriteLine(String.Format("Dublicate property is found: {0} in node: {1}", propertyName, node.Name));
                            continue;
                        }

                        properties.Add(propertyName, "\"" + node.Attributes["Value"].Value + "\"");
                    }

                }
                else
                {
                    XmlNodeList list = doc.SelectNodes("//node()[text() != '']");

                    foreach (XmlNode node in list)
                    {
                        String propertyName = GetPropertyByNode(node);
                        if (properties.ContainsKey(propertyName))
                        {
                            System.Console.WriteLine(String.Format("Dublicate property is found: {0} in node: {1}", propertyName, node.Name));
                            continue;
                        }

                        properties.Add(propertyName, "\"" + node.InnerText + "\"");
                    }
                }

            }
            catch (IOException ex)
            {
            }
            catch (XmlException ex)
            {
            }
            finally
            {

            }

            return properties;
        }

        public static string GetPropertyByNode(XmlNode node)
        {
            StringBuilder st = new StringBuilder();

            return GetPropertyByNode(node, ref st);
        }


        static String GetPropertyByNode(XmlNode node, ref StringBuilder st)
        {
            st.Insert(0, node.Name);
            st.Insert(0, ".");

            if (!node.ParentNode.Name.Equals("root"))
                return GetPropertyByNode(node.ParentNode, ref st);
            else
            {
                st.Remove(0, 1);
                return st.ToString().ToUpper();
            }
        }

        static String ConvertDictionaryToCommandLine(Dictionary<String, String> properties)
        {
            StringBuilder st = new StringBuilder();

            foreach (String key in properties.Keys)
            {
                if (String.IsNullOrEmpty(properties[key]))
                    continue;

                st.AppendFormat("{0}={1} ", key, properties[key]);
            }

            return st.ToString();
        }
    }
}
